package cn.thornbird.orgsync.util;

import cn.thornbird.orgsync.entity.VerificationCode;
import cn.thornbird.orgsync.entity.status.VerificationCodeUsage;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;

public class VerificationCodeUtil {

    public static final String VERIFICATION_CODE_KEY_PREFIX = "orgsync:verification_code:";

    public static final long VERIFICATION_CODE_TIMEOUT = 300000;

    public static final String DIGITS = "8214935607";

    public static final int CODE_LENGTH = 4;

    public static String generateVerificationCode() {
        Random random = new SecureRandom();
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < CODE_LENGTH; i++) {
            int randomIndex = random.nextInt(DIGITS.length());
            stringBuilder.append(DIGITS.charAt(randomIndex));
        }
        return stringBuilder.toString();
    }

    public static void addVerificationCode(StringRedisTemplate redisTemplate, VerificationCode verificationCode) {
        if (!verificationCode.getSuccess()) {
            return;
        }
        String key = VERIFICATION_CODE_KEY_PREFIX + verificationCode.getMobile();
        List<VerificationCodeObject> list = getVerificationCodeList(redisTemplate, verificationCode.getMobile());
        VerificationCodeObject item = new VerificationCodeObject();
        item.setId(verificationCode.getId());
        item.setCode(verificationCode.getCode());
        item.setUsage(verificationCode.getUsage());
        item.setCreatedAt(new Date().getTime());
        list.add(item);
        redisTemplate.opsForValue().set(key, JsonUtil.toJsonString(list));
    }

    public static String findVerificationCode(StringRedisTemplate redisTemplate, String mobile, String code,
                                              VerificationCodeUsage usage) {
        String id = null;
        List<VerificationCodeObject> list = getVerificationCodeList(redisTemplate, mobile);
        for (int i = list.size() - 1; i >= 0; i--) {
            VerificationCodeObject item = list.get(i);
            if (item.getCode().equals(code) && item.getUsage().equals(usage)) {
                id = item.getId();
                break;
            }
        }
        return id;
    }

    public static String removeVerificationCode(StringRedisTemplate redisTemplate, String mobile, String code,
                                                VerificationCodeUsage usage) {
        String id = null;
        String key = VERIFICATION_CODE_KEY_PREFIX + mobile;
        List<VerificationCodeObject> list = getVerificationCodeList(redisTemplate, mobile);
        for (int i = list.size() - 1; i >= 0; i--) {
            VerificationCodeObject item = list.get(i);
            if (item.getCode().equals(code) && item.getUsage().equals(usage)) {
                id = item.getId();
                list.remove(i);
                break;
            }
        }
        if (id != null) {
            redisTemplate.opsForValue().set(key, JsonUtil.toJsonString(list));
        }
        return id;
    }

    public static List<VerificationCodeObject> getVerificationCodeList(StringRedisTemplate redisTemplate,
                                                                       String mobile) {
        String key = VERIFICATION_CODE_KEY_PREFIX + mobile;
        String value = redisTemplate.opsForValue().get(key);
        List<VerificationCodeObject> list = new ArrayList<>();
        if (!StringUtils.isEmpty(value)) {
            list = JsonUtil.parseObject(value, new TypeReference<List<VerificationCodeObject>>() {});
        }
        int size = list.size();
        long now = new Date().getTime();
        for (int i = list.size() - 1; i >= 0; i--) {
            VerificationCodeObject item = list.get(i);
            if (now - item.getCreatedAt() >= VERIFICATION_CODE_TIMEOUT) {
                list.remove(i);
            }
        }
        if (list.size() < size) {
            redisTemplate.opsForValue().set(key, JsonUtil.toJsonString(list));
        }
        return list;
    }


    @Data
    static class VerificationCodeObject {

        private String id;

        private String code;

        private VerificationCodeUsage usage;

        private long createdAt;

    }

}
